
import { GpEntity } from "../GpEntity";
import GpWorld, { GpWorldLayer } from "../GpWorld";
import { GpEventDef } from "../../m/GpEventDef";
import { _decorator, Component, isValid, Node } from 'cc';
import { NodePoolMap } from "../../../../../extensions/cocos-scaffold-3x/assets/ui/NodePoolMap";
import { BaseComponent } from "../../../../../extensions/cocos-scaffold-3x/assets/ui/base/BaseComponent";
import { gg } from "../../../../Game";
import { EcsEntity, EcsEntityGroup } from "ecs-ts";
const { ccclass, property } = _decorator;

export class MakeConfig {
    constructor(
        public entityGroup: EcsEntityGroup,
        public validator: (ecsEntity: EcsEntity) => boolean,
        public getPath: (ecsEntity: EcsEntity) => string,
        public onNodeAdd: (gpEntity: GpEntity) => void,
        public layer = GpWorldLayer.bottom,
        public poolMap: NodePoolMap = new NodePoolMap(),
        public onInit?: (config: MakeConfig) => void,
    ) { }
}

export class GpMakerProp {
    constructor(
        public world: GpWorld,
        public makeConfigArr: MakeConfig[] = []
    ) { }
}
@ccclass
export default class GpMaker extends BaseComponent<GpMakerProp> {

    onInit(): void {
        const gpWorld = this.prop.world
        this.prop.makeConfigArr.forEach(
            (config) => {
                config.onInit&&config.onInit(config);
                this.syncEntitysFromEcsWorld(config);
            }
        )
        gg.eventTarget.on(GpEventDef.onCreateEcsEntity, (ecsEntity: EcsEntity) => {
            // console.log("onCreateEcsEntity", ecsEntity);

            const config = this.prop.makeConfigArr.find(i => i.validator(ecsEntity))
            if (config) {
                this.createEntityByEcsEntity(ecsEntity, config)
            }
        }, this)
        gg.eventTarget.on(GpEventDef.onRemoveEcsEntity, (ecsEntity: EcsEntity) => {
            // console.log("onRemoveEcsEntity", ecsEntity);
            
            const config = this.prop.makeConfigArr.find(i => i.validator(ecsEntity))
            if (config) {
                const entity = gpWorld.entityMap.get(ecsEntity.id)
                if (entity) {
                    config.poolMap.backNode(entity.node, config.getPath(ecsEntity))
                    gpWorld.removeMapEntity(ecsEntity.id)
                }
            }
        }, this)
    }

    onDestroy() {
        gg.eventTarget.targetOff(this)
    }

    async createEntityByEcsEntity(ecsEntity: EcsEntity, makeConfig: MakeConfig) {

        const world = this.prop.world
        const ecsWorld = world.prop.ecsWorld
        const valid = makeConfig.validator(ecsEntity)
        if (valid) {
            const entityId = ecsEntity.id
            const path = makeConfig.getPath(ecsEntity)
            if (!path) {
                return null
            }
            const node = await makeConfig.poolMap.makeNode(path)
            if (!node) { return null }
            if (!isValid(this.node, true)) {
                return null
            }
            if (ecsWorld.getEntity(entityId)) {
                const entity = world.addEntity(node.getComponent(GpEntity), ecsEntity, makeConfig.layer)
                makeConfig.onNodeAdd(entity)
            } else {
                makeConfig.poolMap.backNode(node, path)
            }
            return node
        }

        return null
    }
    syncEntitysFromEcsWorld(config: MakeConfig) {
        config.entityGroup.forEach((ecsEntity) => {
            this.createEntityByEcsEntity(ecsEntity, config)
        })
    }
}